amends "../snippetTest.pkl"

local list1 = List(1, 2, 3)
local list2 = List(1, 2, 3, 4, 5)
local list3 = List(1, 2, 3, 2, 1)
local comparator = (x, y) -> x < y

facts {
  ["isEmpty"] {
    List().isEmpty
    !list1.isEmpty
  }

  ["every()"] {
    list1.every((x) -> x <= 3)
    !list1.every((x) -> x > 2)
  }

  ["any()"] {
    list1.any((x) -> x > 2)
    !list1.any((x) -> x > 3)
  }

  ["contains()"] {
    list1.contains(2)
    !list1.contains(4)
  }

  ["startsWith()"] {
    list1.startsWith(List())
    list1.startsWith(List(1, 2))
    !list1.startsWith(List(1, 3))
  }

  ["endsWith()"] {
    list1.endsWith(List())
    list1.endsWith(List(2, 3))
    !list1.endsWith(List(1, 3))
  }

  ["isDistinct"] {
    list1.isDistinct
    List(1, "1").isDistinct
    List().isDistinct
    !List(1, 2, 1).isDistinct
    !List("Pigeon", "Barn Owl", "Pigeon", "Parrot").isDistinct
  }

  ["isDistinctBy()"] {
    list1.isDistinctBy((it) -> it)
    List("Pigeon", "Barn Owl", "Parrot").isDistinctBy((it) -> it.reverse())
    List().isDistinctBy((it) -> 42)
    !list1.isDistinctBy((it) -> it.isOdd)
    !list1.isDistinctBy((it) -> 42)
  }
}

examples {
  ["every"] {
    module.catch(() -> list1.every((x) -> "wrong type"))
  }

  ["any"] {
    module.catch(() -> list1.any((x) -> "wrong type"))
  }

  ["length"] {
    list1.length
  }

  ["filter()"] {
    list1.filter((x) -> x > 1)
    list1.filter((x) -> x > 3)
    module.catch(() -> list1. filter((x) -> "wrong type"))
  }

  ["map()"] {
    list1.map((x) -> x * 2)
    list1.map((x) -> List(x, x))
  }

  ["flatMap()"] {
    list1.flatMap((x) -> List(x, x + 1))
    module.catch(() -> list1.flatMap((x) -> "wrong type"))
  }

  ["flatten()"] {
    List(List(1, 2), List(2, 3), List(4, 5)).flatten()
    List(Set(1, 2), Set(2, 3), Set(4, 5)).flatten()
    List(new Listing { 1; 2 }, new Listing { 2; 3 }, new Listing { 4; 5 }).flatten()
    List(List(1, 2), Set(2, 3), new Listing { 4; 5 }).flatten()
    List(List(), Set(), new Listing {}).flatten()
  }

  ["first"] {
    list1.first
  }

  ["rest"] {
    list1.rest
  }

  ["last"] {
    list1.last
  }

  ["single"] {
    List(1).single
  }

  ["count()"] {
    list1.count((x) -> x >= 2)
    list1.count((x) -> true)
    list1.count((x) -> false)
    module.catch(() -> list1.count((x) -> "wrong type"))
  }

  ["find()"] {
    list1.find((x) -> x >= 2)
    list1.find((x) -> true)
    module.catch(() -> list1.find((x) -> "wrong type"))
  }

  ["findLast()"] {
    list1.findLast((x) -> x >= 2)
    list1.findLast((x) -> true)
    module.catch(() -> list1.findLast((x) -> "wrong type"))
  }

  ["indexOf()"] {
    list1.indexOf(2)
    List(1,2,3,2,1).indexOf(2)
  }

  ["lastIndexOf()"] {
    list1.lastIndexOf(2)
    List(1,2,3,2,1).lastIndexOf(2)
  }

  ["findIndex()"] {
    list1.findIndex((x) -> x >= 2)
    List(1,2,3,2,1).findIndex((x) -> x >= 2)
    module.catch(() -> list1.findIndex((x) -> "wrong type"))
  }

  ["findLastIndex()"] {
    list1.findLastIndex((x) -> x >= 2)
    List(1,2,3,2,1).findLastIndex((x) -> x >= 2)
    module.catch(() -> list1.findLastIndex((x) -> "wrong type"))
  }

  ["take()"] {
    list1.take(0)
    list1.take(2)
    list1.take(4)
  }

  ["takeWhile()"] {
    list1.takeWhile((x) -> true)
    list1.takeWhile((x) -> false)
    list1.takeWhile((x) -> x < 3)
    module.catch(() -> list1.takeWhile((x) -> "wrong type"))
  }

  ["takeLast()"] {
    list1.takeLast(0)
    list1.takeLast(2)
    list1.takeLast(4)
  }

  ["takeLastWhile()"] {
    list1.takeLastWhile((x) -> true)
    list1.takeLastWhile((x) -> false)
    list1.takeLastWhile((x) -> x > 1)
    module.catch(() -> list1.takeLastWhile((x) -> "wrong type"))
  }

  ["drop()"] {
    list1.drop(0)
    list1.drop(2)
    list1.drop(4)
  }

  ["dropWhile()"] {
    list1.dropWhile((x) -> true)
    list1.dropWhile((x) -> false)
    list1.dropWhile((x) -> x < 3)
    module.catch(() -> list1.dropWhile((x) -> "wrong type"))
  }

  ["dropLast()"] {
    list1.dropLast(0)
    list1.dropLast(2)
    list1.dropLast(4)
  }

  ["dropLastWhile()"] {
    list1.dropLastWhile((x) -> true)
    list1.dropLastWhile((x) -> false)
    list1.dropLastWhile((x) -> x > 1)
    module.catch(() -> list1.dropLastWhile((x) -> "wrong type"))
  }

  ["fold()"] {
    list1.fold(0, (acc, x) -> acc + x)
    list1.fold(List(), (acc, x) -> acc.add(x))
    List(1).fold(0, (acc, x) -> acc + x)
    List().fold(0, (acc, x) -> acc + x)
  }

  ["foldBack()"] {
    list1.foldBack(0, (x, acc) -> x + acc)
    list1.foldBack(List(), (x, acc) -> acc.add(x))
    List(1).foldBack(0, (x, acc) -> x + acc)
    List().foldBack(0, (x, acc) -> x + acc)
  }

  ["reduce()"] {
    list1.reduce((x, y) -> x + y)
    List(1).reduce((x, y) -> x + y)
    module.catch(() -> List().reduce((x, y) -> x + y))
  }

  ["groupBy()"] {
    list2.groupBy((x) -> x)
    list3.groupBy((x) -> x)
    list2.groupBy((x) -> x.isOdd)
    list3.groupBy((x) -> true)
    List().groupBy((x) -> x)
  }

  ["repeat()"] {
    list1.repeat(0)
    list1.repeat(1)
    list1.repeat(5)
    List().repeat(0)
    List().repeat(1)
    List().repeat(5)
    module.catch(() -> list1.repeat(-1))
  }

  ["sortWith()"] {
    List().sortWith(comparator)
    List(3, 1, 1, 2, 1).sortWith(comparator)
    List(3, 1, 2, 5, 4).sortWith(comparator)
  }

  ["replaceRange()"] {
    list2.replaceRange(1, 4, List(9, 8))
    list2.replaceRange(1, 4, List(9))
    list2.replaceRange(1, 4, List())
    list2.replaceRange(1, 1, List(9, 8))
    list2.replaceRange(1, 1, List(9))
    list2.replaceRange(1, 1, List())
    module.catch(() -> list2.replaceRange(-1, 2, List(1)))
    module.catch(() -> list2.replaceRange(3, 6, List(1)))
  }

  ["toList()"] {
    list1.toList()
    list2.toList()
    list3.toList()
  }

  ["toSet()"] {
    list1.toSet()
    list2.toSet()
    list3.toSet()
    List(
      new Dynamic { a = 1 },
      new Dynamic { b = 2 },
      new Dynamic { a = 1 }
    ).toSet()
  }

  ["toMap()"] {
    list1.toMap((x) -> x, (x) -> 2 * x)
    local persons = List(
      new Dynamic { name = "Pigeon"; age = 40 },
      new Dynamic { name = "Parrot"; age = 30 }
    )
    persons.toMap((p) -> p.name, (p) -> p)
  }

  ["lastIndex"] {
    list1.lastIndex
    List().lastIndex
  }

  ["add()"] {
    List().add(42)
    list1.add(42)
  }

  ["replace()"] {
    list1.replace(0, 42)
    list1.replace(1, 42)
    list1.replace(2, 42)
    module.catch(() -> list1.replace(-1, 42))
    module.catch(() -> list1.replace(3, 42))
    module.catch(() -> List().replace(0, 42))
  }

  ["minWith()"] {
    list1.minWith(comparator)
    List(1).minWith(comparator)
    module.catch(() -> List().minWith(comparator))
  }

  ["maxWith()"] {
    list1.maxWith(comparator)
    List(1).maxWith(comparator)
    module.catch(() -> List().maxWith(comparator))
  }

  ["zip()"] {
    List(1, 2, 3).zip(List(4, 5, 6))
    List(1, 2, 3).zip(List(4, 5, 6, 7, 8))
  }

  ["filterIndexed()"] {
    List(1, 2, 3).filterIndexed((i, n) -> i.isOdd)
    List(1, 2, 3).filterIndexed((i, n) -> i.isEven)
    List(1, 2, 3).filterIndexed((i, n) -> i.isOdd && n > 2)
    List(1, 2, 3).filterIndexed((i, n) -> i.isEven && n > 2)
  }

  ["mapIndexed()"] {
    List(1, 2, 3).mapIndexed((i, n) -> n * i)
    List(1, 2, 3).mapIndexed((i, n) -> i.isOdd && n.isEven)
  }

  ["flatMapIndexed()"] {
    List(1, 2, 3).flatMapIndexed((i, n) -> List(n * i))
    List(1, 2, 3).flatMapIndexed((i, n) -> List(i.isOdd && n.isEven))
  }

  ["foldIndexed()"] {
    list1.foldIndexed(0, (idx, x, y) -> idx + x + y)
    List(1).foldIndexed(0, (idx, x, y) -> idx + x + y)
    List().foldIndexed(0, (idx, x, y) -> idx + x + y)
  }

  ["toListing()"] {
    list1.toListing()
    List().toListing()
  }

  ["toDynamic()"] {
    list1.toDynamic()
    List().toDynamic()
  }

  ["filterNonNull()"] {
    list1.filterNonNull()
    List().filterNonNull()
    List(1, null, 2, null, 3).filterNonNull()
    List(null, null, null).filterNonNull()
  }

  ["mapNonNull()"] {
    list1.mapNonNull((it) -> it)
    list1.mapNonNull((it) -> null)
    List().mapNonNull((it) -> it)
    List(1, null, 2, null, 3).mapNonNull((it) -> it)
  }

  ["filterIsInstance()"] {
    list1.filterIsInstance(Any)
    list1.filterIsInstance(Int)
    list1.filterIsInstance(Number)
    list1.filterIsInstance(Float)
    list1.filterIsInstance(String)
    List(1, "2", 3.0, "4").filterIsInstance(String)
    List().filterIsInstance(String)
  }

  ["distinct"] {
    list1.distinct
    List(1, 2, 1).distinct
    List("Pigeon", "Barn Owl", "Pigeon", "Parrot").distinct
    List(1, "1").distinct
    List().distinct
  }

  ["distinctBy()"] {
    list1.distinctBy((it) -> it)
    list1.distinctBy((it) -> it.isOdd)
    List("Pigeon", "Barn Owl", "Parrot").distinctBy((it) -> it.reverse())
    list1.distinctBy((it) -> 42)
    List().distinctBy((it) -> 42)
  }

  ["split()"] {
    list1.split(0)
    list1.split(1)
    list1.split(2)
    list1.split(3)
    List().split(0)
    module.catch(() -> list1.split(-1))
    module.catch(() -> list1.split(4))
  }

  ["partition()"] {
    list1.partition((it) -> it.isEven)
    list1.partition((it) -> it.isOdd)
    list1.partition((it) -> true)
    list1.partition((it) -> false)
    List().partition((it) -> throw("unreachable"))
  }

  ["min"] {
    list1.min
    List("Pigeon", "Barn Owl", "Parrot").min
    List(3.9, -8.4, 42, -99999).min
    List(42, 42, 42).min
    List(42, 42.0).min
    List(42.0, 42).min
    List(11.gb, 100.mb, 12.tb).min
    List(11.s, 100.ms, 3.d).min
    module.catch(() -> List().min)
    module.catch(() -> List(1, "Pigeon", 3.d).min)
  }

  ["max"] {
    list1.max
    List("Pigeon", "Barn Owl", "Parrot").max
    List(3.9, -8.4, 42, -99999).max
    List(42, 42, 42).max
    List(42, 42.0).max
    List(42.0, 42).max
    List(11.gb, 100.mb, 12.tb).max
    List(11.s, 100.ms, 3.d).max
    module.catch(() -> List().max)
     module.catch(() -> List(1, "Pigeon", 3.d).max)
  }

  ["minBy()"] {
    list1.minBy((it) -> it)
    list1.minBy((it) -> -it)
    List("Pigeon", "Barn Owl", "Parrot").minBy((it) -> it.length)
    List("Pigeon", "Barn Owl", "Parrot").minBy((it) -> it.reverse())
    List(11.gb, 100.mb, 12.tb).minBy((it) -> it.value)
    List(11.gb, 100.mb, 12.tb).minBy((it) -> it)
    List(11.s, 100.ms, 12.min).minBy((it) -> it.value)
    List(11.s, 100.ms, 12.min).minBy((it) -> it)
    module.catch(() -> List().minBy((it) -> it))
    module.catch(() -> List(1, "Pigeon", 3.d).minBy((it) -> it))
  }

  ["maxBy()"] {
    list1.maxBy((it) -> it)
    list1.maxBy((it) -> -it)
    List("Pigeon", "Barn Owl", "Parrot").maxBy((it) -> it.length)
    List("Pigeon", "Barn Owl", "Parrot").maxBy((it) -> it.reverse())
    List(11.gb, 100.mb, 12.tb).maxBy((it) -> it.value)
    List(11.gb, 100.mb, 12.tb).maxBy((it) -> it)
    List(11.s, 100.ms, 12.min).maxBy((it) -> it.value)
    List(11.s, 100.ms, 12.min).maxBy((it) -> it)
    module.catch(() -> List().maxBy((it) -> it))
    module.catch(() -> List(1, "Pigeon", 3.d).maxBy((it) -> it))
  }

  ["sort()"] {
    list1.sort()
    List(3.9, -8.4, 42, -99999).sort()
    List("Pigeon", "Barn Owl", "Parrot").sort()
    List(11.gb, 100.mb, 12.tb).sort()
    List(11.s, 100.ms, 3.d).sort()
    List().sort()
    module.catch(() -> List(1, "Pigeon", 3.d).sort())
  }

  ["sortBy()"] {
    list1.sortBy((it) -> it)
    list1.sortBy((it) -> -it)
    List("Pigeon", "Barn Owl", "Parrot").sortBy((it) -> it.length)
    List("Pigeon", "Barn Owl", "Parrot").sortBy((it) -> it.reverse())
    List(11.gb, 100.mb, 12.tb).sortBy((it) -> it.value)
    List(11.gb, 100.mb, 12.tb).sortBy((it) -> it)
    List().sortBy((it) -> throw("unreachable"))
    List(0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10).sortBy((it) -> 42)
  }

  ["reverse()"] {
    list1.reverse()
    list1.reverse().reverse()
    List(1, "Pigeon", 3.d).reverse()
    List().reverse()
  }
}
